#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Thomas Breuer.
##
##  Copyright of GAP belongs to its developers, whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-2.0-or-later
##
##  This file declares the operations for ideals.
##


#############################################################################
##
##  <#GAPDoc Label="[1]{ideal}">
##  A <E>left ideal</E> in a ring <M>R</M> is a subring of <M>R</M> that
##  is closed under multiplication with elements of <M>R</M> from the left.
##  <P/>
##  A <E>right ideal</E> in a ring <M>R</M> is a subring of <M>R</M> that
##  is closed under multiplication with elements of <M>R</M> from the right.
##  <P/>
##  A <E>two-sided ideal</E> or simply <E>ideal</E> in a ring <M>R</M>
##  is both a left ideal and a right ideal in <M>R</M>.
##  <P/>
##  So being a (left/right/two-sided) ideal is not a property of a domain
##  but refers to the acting ring(s).
##  Hence we must ask, e.&nbsp;g., <C>IsIdeal( </C><M>R, I</M><C> )</C> if we
##  want to know whether the ring <M>I</M> is an ideal in the ring <M>R</M>.
##  The property <Ref Prop="IsTwoSidedIdealInParent"/> can be used to store
##  whether a ring is an ideal in its parent.
##  <P/>
##  (Whenever the term <C>"Ideal"</C> occurs in an identifier without a
##  specifying prefix <C>"Left"</C> or <C>"Right"</C>,
##  this means the same as <C>"TwoSidedIdeal"</C>.
##  Conversely, any occurrence of <C>"TwoSidedIdeal"</C> can be substituted
##  by <C>"Ideal"</C>.)
##  <P/>
##  For any of the above kinds of ideals, there is a notion of generators,
##  namely <Ref Attr="GeneratorsOfLeftIdeal"/>,
##  <Ref Attr="GeneratorsOfRightIdeal"/>, and
##  <Ref Attr="GeneratorsOfTwoSidedIdeal"/>.
##  The acting rings can be accessed as <Ref Attr="LeftActingRingOfIdeal"/>
##  and <Ref Attr="RightActingRingOfIdeal"/>, respectively.
##  Note that ideals are detected from known values of these attributes,
##  especially it is assumed that whenever a domain has both a left and a
##  right acting ring then these two are equal.
##  <P/>
##  Note that we cannot use <Ref Attr="LeftActingDomain"/> and
##  <C>RightActingDomain</C> here,
##  since ideals in algebras are themselves vector spaces, and such a space
##  can of course also be a module for an action from the right.
##  In order to make the usual vector space functionality automatically
##  available for ideals, we have to distinguish the left and right module
##  structure from the additional closure properties of the ideal.
##  <P/>
##  Further note that the attributes denoting ideal generators and acting
##  ring are used to create ideals if this is explicitly wanted, but the
##  ideal relation in the sense of <Ref Oper="IsTwoSidedIdeal"/> is of course
##  independent of the presence of the attribute values.
##  <P/>
##  Ideals are constructed with <Ref Func="LeftIdeal"/>,
##  <Ref Func="RightIdeal"/>, <Ref Func="TwoSidedIdeal"/>.
##  Principal ideals of the form <M>x * R</M>, <M>R * x</M>, <M>R * x * R</M>
##  can also be constructed with a simple multiplication.
##  <P/>
##  Currently many methods for dealing with ideals need linear algebra to
##  work, so they are mainly applicable to ideals in algebras.
##  <P/>
##  <#/GAPDoc>
#T  The sum of two left/right/two-sided ideals with same acting ring can be
#T  formed, it is again an ideal.
#T  The product of two ideals ...
##


#############################################################################
##
#F  TwoSidedIdeal( <R>, <gens>[, "basis"] )
#F  Ideal( <R>, <gens>[, "basis"] )
#F  LeftIdeal( <R>, <gens>[, "basis"] )  . . left ideal in <R> gen. by <gens>
#F  RightIdeal( <R>, <gens>[, "basis"] ) .  right ideal in <R> gen. by <gens>
##
##  <#GAPDoc Label="TwoSidedIdeal">
##  <ManSection>
##  <Func Name="TwoSidedIdeal" Arg='R, gens[, "basis"]'/>
##  <Func Name="Ideal" Arg='R, gens[, "basis"]'/>
##  <Func Name="LeftIdeal" Arg='R, gens[, "basis"]'/>
##  <Func Name="RightIdeal" Arg='R, gens[, "basis"]'/>
##
##  <Description>
##  Let <A>R</A> be a ring, and <A>gens</A> a list of collection of elements
##  in <A>R</A>.
##  <Ref Func="TwoSidedIdeal"/>, <Ref Func="LeftIdeal"/>,
##  and <Ref Func="RightIdeal"/> return the two-sided,
##  left, or right ideal, respectively,
##  <M>I</M> in <A>R</A> that is generated by <A>gens</A>.
##  The ring <A>R</A> can be accessed as <Ref Attr="LeftActingRingOfIdeal"/>
##  or <Ref Attr="RightActingRingOfIdeal"/> (or both) of <M>I</M>.
##  <P/>
##  If <A>R</A> is a left <M>F</M>-module then also <M>I</M> is a left
##  <M>F</M>-module,
##  in particular the <Ref Attr="LeftActingDomain"/> values of
##  <A>R</A> and <M>I</M> are equal.
##  <P/>
##  If the optional argument <C>"basis"</C> is given then <A>gens</A> are
##  assumed to be a list of basis vectors of
##  <M>I</M> viewed as a free <M>F</M>-module.
##  (This is mainly applicable to ideals in algebras.)
##  In this case, it is <E>not</E> checked whether <A>gens</A> really is
##  linearly independent and whether <A>gens</A> is a subset of <A>R</A>.
##  <P/>
##  <Ref Func="Ideal"/> is simply a synonym of <Ref Func="TwoSidedIdeal"/>.
##  <P/>
##  <Example><![CDATA[
##  gap> R:= Integers;;
##  gap> I:= Ideal( R, [ 2 ] );
##  <two-sided ideal in Integers, (1 generators)>
##  ]]></Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareGlobalFunction( "TwoSidedIdeal" );
DeclareSynonym( "Ideal", TwoSidedIdeal );
DeclareGlobalFunction( "LeftIdeal" );
DeclareGlobalFunction( "RightIdeal" );


#############################################################################
##
#F  TwoSidedIdealNC( <R>, <gens>[, "basis"] )
#F  IdealNC( <R>, <gens>[, "basis"] )
#F  LeftIdealNC( <R>, <gens>[, "basis"] )
#F  RightIdealNC( <R>, <gens>[, "basis"] )
##
##  <#GAPDoc Label="TwoSidedIdealNC">
##  <ManSection>
##  <Func Name="TwoSidedIdealNC" Arg='R, gens[, "basis"]'/>
##  <Func Name="IdealNC" Arg='R, gens[, "basis"]'/>
##  <Func Name="LeftIdealNC" Arg='R, gens[, "basis"]'/>
##  <Func Name="RightIdealNC" Arg='R, gens[, "basis"]'/>
##
##  <Description>
##  The effects of <Ref Func="TwoSidedIdealNC"/>, <Ref Func="LeftIdealNC"/>,
##  and <Ref Func="RightIdealNC"/> are the same as
##  <Ref Func="TwoSidedIdeal"/>, <Ref Func="LeftIdeal"/>,
##  and <Ref Func="RightIdeal"/>, respectively,
##  but they do not check whether all entries of <A>gens</A> lie in <A>R</A>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareGlobalFunction( "TwoSidedIdealNC" );
DeclareSynonym( "IdealNC", TwoSidedIdealNC );
DeclareGlobalFunction( "LeftIdealNC" );
DeclareGlobalFunction( "RightIdealNC" );


#############################################################################
##
#O  IsTwoSidedIdeal( <R>, <I> )
#O  IsLeftIdeal( <R>, <I> )
#O  IsRightIdeal( <R>, <I> )
#P  IsTwoSidedIdealInParent( <I> )
#P  IsLeftIdealInParent( <I> )
#P  IsRightIdealInParent( <I> )
##
##  <#GAPDoc Label="IsTwoSidedIdeal">
##  <ManSection>
##  <Oper Name="IsTwoSidedIdeal" Arg='R, I'/>
##  <Oper Name="IsLeftIdeal" Arg='R, I'/>
##  <Oper Name="IsRightIdeal" Arg='R, I'/>
##  <Prop Name="IsTwoSidedIdealInParent" Arg='I'/>
##  <Prop Name="IsLeftIdealInParent" Arg='I'/>
##  <Prop Name="IsRightIdealInParent" Arg='I'/>
##
##  <Description>
##  The properties <Ref Prop="IsTwoSidedIdealInParent"/> etc., are attributes
##  of the ideal, and once known they are stored in the ideal.
##  <Example><![CDATA[
##  gap> A:= FullMatrixAlgebra( Rationals, 3 );
##  ( Rationals^[ 3, 3 ] )
##  gap> I:= Ideal( A, [ Random( A ) ] );
##  <two-sided ideal in ( Rationals^[ 3, 3 ] ), (1 generators)>
##  gap> IsTwoSidedIdeal( A, I );
##  true
##  ]]></Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InParentFOA( "IsTwoSidedIdeal", IsRing, IsRing, DeclareProperty );
InParentFOA( "IsLeftIdeal", IsRing, IsRing, DeclareProperty );
InParentFOA( "IsRightIdeal", IsRing, IsRing, DeclareProperty );

DeclareSynonym( "IsIdeal", IsTwoSidedIdeal );
DeclareSynonym( "IsIdealOp", IsTwoSidedIdealOp );
DeclareSynonymAttr( "IsIdealInParent", IsTwoSidedIdealInParent );

InstallTrueMethod( IsLeftIdealInParent, IsTwoSidedIdealInParent );
InstallTrueMethod( IsRightIdealInParent, IsTwoSidedIdealInParent );
InstallTrueMethod( IsTwoSidedIdealInParent,
    IsLeftIdealInParent and IsRightIdealInParent );


#############################################################################
##
#O  TwoSidedIdealByGenerators( <R>, <gens> )  . . ideal in <R> gen. by <gens>
#O  IdealByGenerators( <R>, <gens> )
##
##  <#GAPDoc Label="TwoSidedIdealByGenerators">
##  <ManSection>
##  <Oper Name="TwoSidedIdealByGenerators" Arg='R, gens'/>
##  <Oper Name="IdealByGenerators" Arg='R, gens'/>
##
##  <Description>
##  <Ref Oper="TwoSidedIdealByGenerators"/> returns the ring that is
##  generated by the elements of the collection <A>gens</A> under addition,
##  multiplication, and multiplication with elements of the ring <A>R</A>
##  from the left and from the right.
##  <P/>
##  <A>R</A> can be accessed by <Ref Attr="LeftActingRingOfIdeal"/> or
##  <Ref Attr="RightActingRingOfIdeal"/>,
##  <A>gens</A> can be accessed by <Ref Attr="GeneratorsOfTwoSidedIdeal"/>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareOperation( "TwoSidedIdealByGenerators", [ IsRing, IsListOrCollection ] );

DeclareSynonym( "IdealByGenerators", TwoSidedIdealByGenerators );


#############################################################################
##
#O  LeftIdealByGenerators( <R>, <gens> )
##
##  <#GAPDoc Label="LeftIdealByGenerators">
##  <ManSection>
##  <Oper Name="LeftIdealByGenerators" Arg='R, gens'/>
##
##  <Description>
##  <Ref Oper="LeftIdealByGenerators"/> returns the ring that is generated by
##  the elements of the collection <A>gens</A> under addition,
##  multiplication, and multiplication with elements of the ring <A>R</A>
##  from the left.
##  <P/>
##  <A>R</A> can be accessed by <Ref Attr="LeftActingRingOfIdeal"/>,
##  <A>gens</A> can be accessed by <Ref Attr="GeneratorsOfLeftIdeal"/>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareOperation( "LeftIdealByGenerators", [ IsRing, IsListOrCollection ] );


#############################################################################
##
#O  RightIdealByGenerators( <R>, <gens> )
##
##  <#GAPDoc Label="RightIdealByGenerators">
##  <ManSection>
##  <Oper Name="RightIdealByGenerators" Arg='R, gens'/>
##
##  <Description>
##  <Ref Oper="RightIdealByGenerators"/> returns the ring that is generated
##  by the elements of the collection <A>gens</A> under addition,
##  multiplication, and multiplication with elements of the ring <A>R</A>
##  from the right.
##  <P/>
##  <A>R</A> can be accessed by <Ref Attr="RightActingRingOfIdeal"/>,
##  <A>gens</A> can be accessed by <Ref Attr="GeneratorsOfRightIdeal"/>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareOperation( "RightIdealByGenerators", [ IsRing, IsListOrCollection ] );


#############################################################################
##
#A  GeneratorsOfTwoSidedIdeal( <I> )
#A  GeneratorsOfIdeal( <I> )
##
##  <#GAPDoc Label="GeneratorsOfTwoSidedIdeal">
##  <ManSection>
##  <Attr Name="GeneratorsOfTwoSidedIdeal" Arg='I'/>
##  <Attr Name="GeneratorsOfIdeal" Arg='I'/>
##
##  <Description>
##  is a list of generators for the ideal <A>I</A>, with respect to
##  the action of the rings that are stored as the values of
##  <Ref Attr="LeftActingRingOfIdeal"/> and
##  <Ref Attr="RightActingRingOfIdeal"/>, from the left and from the right,
##  respectively.
##  <P/>
##  <Example><![CDATA[
##  gap> A:= FullMatrixAlgebra( Rationals, 3 );;
##  gap> I:= Ideal( A, [ One( A ) ] );;
##  gap> GeneratorsOfIdeal( I );
##  [ [ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ] ] ]
##  ]]></Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareAttribute( "GeneratorsOfTwoSidedIdeal", IsRing );

DeclareSynonymAttr( "GeneratorsOfIdeal", GeneratorsOfTwoSidedIdeal );


#############################################################################
##
#A  GeneratorsOfLeftIdeal( <I> )
##
##  <#GAPDoc Label="GeneratorsOfLeftIdeal">
##  <ManSection>
##  <Attr Name="GeneratorsOfLeftIdeal" Arg='I'/>
##
##  <Description>
##  is a list of generators for the left ideal <A>I</A>, with respect to the
##  action from the left of the ring that is stored as the value of
##  <Ref Attr="LeftActingRingOfIdeal"/>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareAttribute( "GeneratorsOfLeftIdeal", IsRing );


#############################################################################
##
#A  GeneratorsOfRightIdeal( <I> )
##
##  <#GAPDoc Label="GeneratorsOfRightIdeal">
##  <ManSection>
##  <Attr Name="GeneratorsOfRightIdeal" Arg='I'/>
##
##  <Description>
##  is a list of generators for the right ideal <A>I</A>, with respect to the
##  action from the right of the ring that is stored as the value of
##  <Ref Attr="RightActingRingOfIdeal"/>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareAttribute( "GeneratorsOfRightIdeal", IsRing );


#############################################################################
##
#A  LeftActingRingOfIdeal( <I> )
#A  RightActingRingOfIdeal( <I> )
##
##  <#GAPDoc Label="LeftActingRingOfIdeal">
##  <ManSection>
##  <Attr Name="LeftActingRingOfIdeal" Arg='I'/>
##  <Attr Name="RightActingRingOfIdeal" Arg='I'/>
##
##  <Description>
##  returns the left (resp. right) acting ring of an ideal <A>I</A>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareAttribute( "LeftActingRingOfIdeal", IsRing );

DeclareAttribute( "RightActingRingOfIdeal", IsRing );


#############################################################################
##
#O  AsLeftIdeal( <R>, <S> )
#O  AsRightIdeal( <R>, <S> )
#O  AsTwoSidedIdeal( <R>, <S> )
##
##  <#GAPDoc Label="AsLeftIdeal">
##  <ManSection>
##  <Oper Name="AsLeftIdeal" Arg='R, S'/>
##  <Oper Name="AsRightIdeal" Arg='R, S'/>
##  <Oper Name="AsTwoSidedIdeal" Arg='R, S'/>
##
##  <Description>
##  Let <A>S</A> be a subring of the ring <A>R</A>.
##  <P/>
##  If <A>S</A> is a left ideal in <A>R</A> then <Ref Oper="AsLeftIdeal"/>
##  returns this left ideal, otherwise <K>fail</K> is returned.
##  <P/>
##  If <A>S</A> is a right ideal in <A>R</A> then <Ref Oper="AsRightIdeal"/>
##  returns this right ideal, otherwise <K>fail</K> is returned.
##  <P/>
##  If <A>S</A> is a two-sided ideal in <A>R</A> then
##  <Ref Oper="AsTwoSidedIdeal"/> returns this two-sided ideal,
##  otherwise <K>fail</K> is returned.
##  <P/>
##  <Example><![CDATA[
##  gap> A:= FullMatrixAlgebra( Rationals, 3 );;
##  gap> B:= DirectSumOfAlgebras( A, A );
##  <algebra over Rationals, with 6 generators>
##  gap> C:= Subalgebra( B, Basis( B ){[1..9]} );
##  <algebra over Rationals, with 9 generators>
##  gap> I:= AsTwoSidedIdeal( B, C );
##  <two-sided ideal in <algebra of dimension 18 over Rationals>, 
##    (9 generators)>
##  ]]></Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareOperation( "AsLeftIdeal", [ IsRing, IsRing ] );
DeclareOperation( "AsRightIdeal", [ IsRing, IsRing ] );
DeclareOperation( "AsTwoSidedIdeal", [ IsRing, IsRing ] );
